﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ComponentModel.Composition;

using NuMetaheuristics;
using NuMetaheuristics.Utility;

namespace NuMetaheuristics.Operators.Value
{
    /// <summary>
    /// Initialize a value within the range from Min to Max. Default range is 
    /// 0.0 to 1.0.
    /// </summary>
    [Export(typeof(IUnaryOperator<double>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class DoubleRandomInitializer : IUnaryOperator<double>, IDeserializationCallback
    {
        private RandomNumberGenerator _rng;

        [DataMember]
        public double Min { get; set; }
        [DataMember]
        public double Max { get; set; }

        public DoubleRandomInitializer()
        {
            _rng = new RandomNumberGenerator();
            Min = 0.0;
            Max = 1.0;
        }

        public DoubleRandomInitializer(double min, double max)
        {
            if (max <= min)
                throw new ArgumentOutOfRangeException();

            _rng = new RandomNumberGenerator();
            Min = min;
            Max = max;
        }

        public void Operate(ref double operand)
        {
            double a = Max - Min;
            double b = _rng.NextDouble() * a;
            operand = b + Min;
        }

        public void OnDeserialization(object sender)
        {
            _rng = new RandomNumberGenerator();
        }
    }

    /// <summary>
    /// Initialize a value within the range from Min to Max. Default range is 
    /// 0 to 32767.
    /// </summary>
    [Export(typeof(IUnaryOperator<int>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class IntegerRandomInitializer : IUnaryOperator<int>, IDeserializationCallback
    {
        private RandomNumberGenerator _rng;

        [DataMember]
        public int Min { get; set; }
        [DataMember]
        public int Max { get; set; }

        public IntegerRandomInitializer()
        {
            _rng = new RandomNumberGenerator();
            Min = 0;
            Max = 32767;
        }

        public IntegerRandomInitializer(int min, int max)
        {
            if (max <= min)
                throw new ArgumentOutOfRangeException();

            _rng = new RandomNumberGenerator();
            Min = min;
            Max = max;
        }

        public void Operate(ref int operand)
        {
            operand = _rng.Next(Min, Max);
        }

        public void OnDeserialization(object sender)
        {
            _rng = new RandomNumberGenerator();
            Min = 0;
            Max = 32767;
        }
    }

    /// <summary>
    /// Initialize a value to either true or false.
    /// </summary>
    [Export(typeof(IUnaryOperator<bool>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class BooleanRandomInitializer : IUnaryOperator<bool>, IDeserializationCallback
    {
        private RandomNumberGenerator _rng;
        
        public BooleanRandomInitializer()
            : base()
        {
            _rng = new RandomNumberGenerator();
        }
        
        public void Operate(ref bool operand)
        {
            operand = (_rng.Next(2) == 1) ? true : false;
        }

        public void OnDeserialization(object sender)
        {
            _rng = new RandomNumberGenerator();
        }
    }
}
